/* Copyright - Apache License 2.0
 * 
 * The project "kyou" is
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.kyou.data.dquery;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import net.kyou.exception.KyouErr;
import net.kyou.exception.KyouException;

/**
 * 表示DQuery中的各个段
 * 
 * @author NuclearG (<a href="mailto:nuclearg@163.com">nuclearg@163.com</a>)
 */
class DQuerySegment {
    /**
     * DQuery段的主体
     */
    final String body;
    /**
     * 段的类型
     */
    final SegmentType type;
    /**
     * 下标列表<li>该列表为空表示未指定下标</li><li>该列表为null表示指定所有下标</li>
     */
    final int[] indexes;
    /**
     * 约束条件列表
     */
    final DQueryRestriction[] restrictions;

    /**
     * 初始化一个DQuery段
     */
    DQuerySegment(String query) {
        if (query == null || query.length() == 0)
            throw new KyouException(KyouErr.Style.EmptyDQuerySegment, query.toString());

        // 解析body和restrictions
        this.body = this.body(query);
        ArrayList<DQueryRestriction> restrictions = this.restrictions(query);

        // 遍历并分析restrictions
        Set<Integer> indexes = new HashSet<Integer>();
        SegmentType type = SegmentType.Irrelevant;
        boolean wildchar = false;
        for (int i = 0; i < restrictions.size(); i++) {
            DQueryRestriction restriction = restrictions.get(i);
            if (restrictions.get(i).simple) {
                switch (restrictions.get(i).simpleType) {
                    case ARRAYINDEX:
                        indexes.add(restriction.arrayIndex);
                        break;
                    case FIELD:
                        type = SegmentType.Field;
                        break;
                    case STRUCT:
                        type = SegmentType.Struct;
                        break;
                    case WILDCHAR:
                        wildchar = true;
                        break;
                }
                restrictions.remove(i--);
            }
        }

        if (wildchar)
            this.indexes = null;
        else {
            this.indexes = new int[indexes.size()];
            Integer[] _indexes = indexes.toArray(new Integer[0]);
            for (int i = 0; i < indexes.size(); i++)
                this.indexes[i] = _indexes[i];
        }
        this.type = type;
        this.restrictions = restrictions.toArray(new DQueryRestriction[0]);
    }

    /**
     * 工具函数 解析DQuery段中的主体部分
     */
    private String body(String query) {
        if (query.contains("["))
            return query.substring(query.indexOf('['));
        else
            return query;
    }

    /**
     * 工具函数 解析DQuery段中的约束部分
     */
    private ArrayList<DQueryRestriction> restrictions(String query) {
        ArrayList<DQueryRestriction> restrictions = new ArrayList<DQueryRestriction>();

        if (!query.contains("["))
            return restrictions;
        else {
            if (!query.endsWith("]"))
                throw new KyouException(KyouErr.Style.DQuerySyntaxError, query);

            for (String restriction : query.substring(query.indexOf('['), query.length() - 2).split(","))
                if (restriction.trim().length() != 0)
                    restrictions.add(new DQueryRestriction(restriction.trim()));

            return restrictions;
        }
    }

    /**
     * 段的类型
     */
    enum SegmentType {
        /**
         * 不关心
         */
        Irrelevant,
        /**
         * 域
         */
        Field,
        /**
         * 结构
         */
        Struct
    }
}
